<template>
  <div class="play-audio">
    <h2 style="text-align: center;">播放页面</h2>
    <div style="text-align: center;">
      <label for="name">接收人：</label>
      <input type="text" id="name" v-model="toUserId" class="form-control" />
    </div>
    <div class="main-box">
      本地：
      <video ref="localVideo" class="video" autoplay="autoplay"></video>
      远程：
      <video
        ref="remoteVideo"
        style="margin-left: 20px;"
        class="video"
        height="500px"
        autoplay="autoplay"
      ></video>
    </div>
    <div>
      <el-button @click="requestConnect()" ref="callBtn">开始对讲</el-button>
      <el-button @click="hangupHandle()" ref="hangupBtn">结束对讲</el-button>
    </div>

    <div style="text-align: center;" v-if="showCall">
      <button id="hangup" class="hangup" onclick="hangupVideoButton()">挂断</button>
      <button id="accept" class="accept" onclick="acceptVideoButton()">接受</button>
    </div>
  </div>
</template>

<script>
import { mapGetters } from "vuex";
export default {
  computed: {
    ...mapGetters(["chatMessageStr"])
  },
  data() {
    return {
      toUserId: null,
      localStream: null,
      remoteStream: null,
      localVideo: null,
      remoteVideo: null,
      PeerConnection: null,
      dialogVisible: false,
      msg: "",
      yourConn: null,
      isCaller: false,
      userInfo: {
        userId: localStorage.getItem("userId"),
        userName: localStorage.getItem("userName")
      },
      showCall: false
    };
  },
  mounted() {
    this.remoteVideo = this.$refs.remoteVideo;
    this.localVideo = this.$refs.localVideo;
  },

  /**
   * 监听发送过来的聊天消息
   */
  watch: {
    "chatMessageStr"(newVal, oldVal) {
      //获取消息对象
      // let message = JSON.parse(newVal);
      let message = newVal;
      console.log("接受到的信息--》", message);

      if (message.contentType == "call_start") {
        console.log("被叫方准备初始化webRtc--->");
        //初始化webrtc
        this.initWebRTC();
        setTimeout(() => {
          console.log("被叫方初始化webRtc完毕--->");
          console.log("被叫方初始化webRtc完毕--this.yourConn->", this.yourConn);
        }, 3000);

        //判断是否为推送过来的信令
      } else if (message.contentType == "candidate") {
        //设置信令的应答
        this.toUserId = message.from;
        console.log("this.yourConn--》", this.yourConn);
        console.log("message.content--》", message.content);
        console.log("message.content-candidate-》", message.content.candidate);
        //处理ICE备选
        this.yourConn.addIceCandidate(new RTCIceCandidate(message.content));
      } else if (message.contentType == "text") {
        //弹出提示对话框
        console.log("被叫方接收到视频请求--->", message);

        this.$confirm(message.content, "提示", {
          confirmButtonText: "接受",
          cancelButtonText: "挂断",
          type: "warning"
        })
          .then(() => {
            //接受通话
            this.acceptVideoButton(message);
          })
          .catch(() => {
            //挂断通话
            this.hangupVideoButton(message);
          });
      } else if (message.contentType == "call_back") {
        console.log("主叫方接收到同意视频请求--->", message);

        //弹出提示对话框
        this.$alert(message.to + "接受了你的视频通话", "公告", {
          confirmButtonText: "确定"
        });
        //处理视频通话请求回调
        this.handleCallBack(message);
      } else if (message.contentType == "offer") {
        //处理视频通话请求回调
        this.handleOffer(message);
      } else if (message.contentType == "answer") {
        //处理视频通话应答
        this.handleAnswer(message);
      }
    }
  },
  methods: {
    //发起视频通话
    requestConnect() {
      if (!this.toUserId) {
        alert("请输入对方id");
        return false;
      }

      //设置当前用户为主叫
      this.isCaller = true;
      console.log("主叫方准备开始初始化webrtc-->");
      //初始化webrtc,获取设备，创建连接，将音视频流绑定到视频标签上，同时设置一些监听事件，比如对端连接绑定到远端的视频标签上。.....
      this.initWebRTC();

      setTimeout(() => {
        //推送通话信息
        let mesg1 = {
          from: this.userInfo.userId,
          to: this.toUserId,
          contentType: "call_start",
          content: ""
        };
        console.log("call_start：", mesg1);
        this.$websocket.Send(mesg1);

        //推送通话信息
        let mesg = {
          from: this.userInfo.userId,
          to: this.toUserId,
          contentType: "text",
          content: this.userInfo.userName + "请求与你视频通话"
        };
        console.log("推送通话信息：", mesg);
        this.$websocket.Send(mesg);
      }, 3000);
    },
    //初始化webrtc
    initWebRTC() {
      console.log("当前PeerConnection--->", this.PeerConnection);

      if (this.PeerConnection !== null && this.PeerConnection !== undefined) {
        return;
      }

      this.PeerConnection =
        window.webkitRTCPeerConnection ||
        window.mozRTCPeerConnection ||
        window.RTCPeerConnection ||
        undefined;

      console.log("赋值后PeerConnection--->", this.PeerConnection);
      //  RTCSessionDescription = (window.webkitRTCSessionDescription || window.mozRTCSessionDescription || window.RTCSessionDescription || undefined);

      if (navigator.mediaDevices === undefined) {
        navigator.mediaDevices = {};
      }
      if (navigator.mediaDevices.getUserMedia === undefined) {
        navigator.mediaDevices.getUserMedia = function(constraints) {
          var getUserMedia =
            navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
          if (!getUserMedia) {
            return Promise.reject(
              new Error("getUserMedia is not implemented in this browser")
            );
          }
          return new Promise(function(resolve, reject) {
            getUserMedia.call(navigator, constraints, resolve, reject);
          });
        };
      }

      var mediaOpts = {
        // audio: audioVideoDevices.audioinput || audioVideoDevices.audiooutput,
        audio: true,
        //判断如果是视频通话就调用前置摄像头，facingMode: "user"调用前置摄像头，如果不是视屏通话就不使用摄像头
        video: {
          facingMode: "user"
        }
      };

      navigator.mediaDevices
        .getUserMedia(mediaOpts)
        .then(stream => {
          // 成功获取媒体流后调用成功回调函数
          this.successFunc(stream);
        })
        .catch(error => {
          // 获取媒体流失败时调用失败回调函数
          this.errorFunc(error);
        });
    },

    //获取摄像头权限成功时执行的回调
    successFunc(myStream) {
      let _that = this;
      console.log("摄像头权限获取成功--->", myStream);

      //播放本地摄像头捕捉到的画面
      this.localVideo.srcObject = myStream;

      //using Google public stun server,turn中继服务器需要自己搭建，可参考网上coturn搭建教程
      //此处指定了服务器，是 Google 的 STUN 服务器，
      var configuration = {
        iceServers: [
          {
            urls: "stun:stun.l.google.com:19302"
          }
        ]
      };

      //在浏览器之间建立点对点的连接
      this.yourConn = new this.PeerConnection(configuration);

      console.log("主叫方this.yourConn--->", this.yourConn);

      // 添加流到对等连接，这里stream 是本地摄像头或麦克风捕获的音视频流，使用 addStream 方法将这个流添加到对等连接中，以便与远程对等连接共享
      this.yourConn.addStream(myStream);

      //当远程用户向对等连接添加流时，将触发这个事件，并将流设置为远程视频元素 remoteVideo 的源对象，以显示远程用户的视频。即对方接受视频通过后就会触发当前方法
      this.yourConn.onaddstream = function(e) {
        console.log(
          "被叫用户向对等连接添加流--this.remoteVideo->",
          _that.remoteVideo
        );
        console.log("被叫用户向对等连接添加流--->", e.stream);

        //将远程流显示到页面
        _that.remoteVideo.srcObject = e.stream;
      };

      // 在发现新的 ICE 候选时执行的回调
      this.yourConn.onicecandidate = function(event) {
        //是否存在 ICE 候选
        if (event.candidate) {
          //如果存在 ICE 候选，则通过 WebSocket 发送 ICE 候选信息给对端

          let mesg = {
            from: _that.userInfo.userId,
            to: _that.toUserId,
            contentType: "candidate",
            content: event.candidate
          };
          console.log("发送ICE候选--->", mesg);
          _that.$websocket.Send(mesg);
        }
      };
    },
    //获取摄像头权限失败时执行的回调
    errorFunc(err) {
      console.log("主叫方获取摄像头权限失败--->", err);
      if ("NotFoundError" == err.name) {
        alert("设备不具备视频、音频条件或没有音视频权限");
      } else {
        alert(err.name);
      }
    },

    //结束通话
    hangupHandle() {},
    //接受视频请求
    acceptVideoButton(message) {
      this.toUserId = message.from;
      var data = {
        contentType: "call_back",
        to: this.toUserId,
        from: this.userInfo.userId,
        content: "accept"
      };
      console.log("被叫方发送接受视频请求--》", data);
      this.$websocket.Send(data);
    },

    //挂断视频聊天
    hangupVideoButton(message) {
      let data = {
        contentType: "leave",
        to: this.toUserId,
        from: this.userInfo.userId,
        content: ""
      };
      this.$websocket.Send(data);
      //关闭视频流和PeerConnection
      this.closeVideoStream();
    },
    //关闭视频流和PeerConnection
    closeVideoStream() {
      try {
        this.localVideo.srcObject.getTracks()[0].stop();
        this.localVideo.srcObject.getTracks()[1].stop();
        this.remoteVideo.srcObject.getTracks()[0].stop();
        this.remoteVideo.srcObject.getTracks()[1].stop();
      } catch (e) {
        console.log(e);
      } finally {
        this.yourConn.close();
        this.PeerConnectionPeerConnection = null;
        this.yourConn.onicecandidate = null;
        this.yourConn.onaddstream = null;

        this.isCaller = false;
      }
    },
    //处理视频请求的响应
    handleCallBack(data) {
      console.log(
        "主叫方开始处理同意视频请求后的响应--- this.yourConn 》",
        this.yourConn
      );
      let _that = this;

      //接受视频
      if (data.content == "accept") {
        //,这个回调函数会在 SDP offer 创建成功后被调用,生成本地端的会话描述（SDP)
        this.yourConn.createOffer(
          function(offer) {
            let sendData = {
              from: _that.userInfo.userId,
              to: _that.toUserId,
              contentType: "offer",
              content: offer
            };
            console.log("offer--->", sendData);
            _that.$websocket.Send(sendData);

            //将这个 SDP offer 设置为本地端的会话描述
            _that.yourConn.setLocalDescription(offer);
          },
          function(error) {
            alert("Error when creating an offer");
          }
        );
      } else {
        //拒绝视频
        //关闭视频流和PeerConnection
        this.closeVideoStream();
      }
    },
    //处理offer请求
    handleOffer(data) {
      let _that = this;
      console.log("被叫方接受到offer--- this.yourConn 》", this.yourConn);
      console.log("被叫方接受到data----- data-- 》", data);
      console.log("data.content------ 》", data.content);
      console.log("data.content.sdp------ 》", data.content.sdp);

      this.yourConn.setRemoteDescription(
        new RTCSessionDescription(data.content)
      );

      //create an answer to an offer
      this.yourConn.createAnswer(
        function(answer) {
          _that.yourConn.setLocalDescription(answer);

          let answerData = {
            from: _that.userInfo.userId,
            to: _that.toUserId,
            contentType: "answer",
            content: answer
          };
          console.log("创建应答数据----- answerData 》", answerData);

          _that.$websocket.Send(answerData);
        },
        function(error) {
          alert("Error when creating an answer");
        }
      );
    },
    //处理应答
    handleAnswer(data) {
      console.log("主叫方接受到应答----- this.yourConn-- 》", this.yourConn);
      console.log("主叫方接受到应答----- data-- 》", data);
      this.yourConn.setRemoteDescription(
        new RTCSessionDescription(data.content)
      );
    }
  }
};
</script>
<style lang="css">
.spreadsheet {
  padding: 0 10px;
  margin: 20px 0;
}

.main-box {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
}
</style>
